package com.clementheliou.cheliou.dal.model.camera.model.builder;

import org.springframework.util.Assert;

import com.clementheliou.cheliou.dal.dao.camera.brand.CameraBrandDAO;
import com.clementheliou.cheliou.dal.dao.camera.model.CameraModelDAO;
import com.clementheliou.cheliou.dal.model.camera.brand.builder.CameraBrandBuilder;
import com.clementheliou.cheliou.dal.model.camera.model.CameraModel;
import com.clementheliou.cheliou.util.builder.ObjectBuilder;

/**
 * Builder used to get {@link CameraModel} instances for test purpose. It must only be used through
 * one of its static factory methods.
 * 
 * @author Clément HELIOU (clement.heliou@gmail.com)
 * @see {@link CameraModel};
 * @see {@link ObjectBuilder}.
 * @since 1.0
 */
public class CameraModelBuilder extends ObjectBuilder<CameraModel> {

	/**
	 * The {@link CameraBrandDAO} to be transmitted to the {@link CameraBrandBuilder} if the
	 * instance must be persisted.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @see {@link CameraBrandBuilder} .
	 * @since 1.0
	 */
	private final CameraBrandDAO cameraBrandDAO;

	/**
	 * The {@link CameraModelDAO} to be used to persist the built instance if needed.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	private final CameraModelDAO cameraModelDAO;

	/**
	 * Private constrauctor from the DAO's to be used.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param cameraBrandDAO the {@link CameraBrandDAO} to be used.
	 * @param cameraModelDAO the {@link CameraModelDAO} to be used.
	 * @since 1.0
	 */
	private CameraModelBuilder(CameraBrandDAO cameraBrandDAO, CameraModelDAO cameraModelDAO) {
		this.cameraBrandDAO = cameraBrandDAO;
		this.cameraModelDAO = cameraModelDAO;
	}

	/**
	 * Static factory method used to get a builder instance for a {@link CameraModel} object that
	 * must be persistent. It's mostly used on data access layer's methods tests.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param cameraBrandDAO the {@link CameraBrandDAO} to be used.
	 * @param cameraModelDAO the {@link CameraModelDAO} to be used.
	 * @return the builder instance to be used.
	 * @since 1.0
	 */
	public static CameraModelBuilder with(CameraBrandDAO cameraBrandDAO, CameraModelDAO cameraModelDAO) {
		return new CameraModelBuilder(cameraBrandDAO, cameraModelDAO);
	}

	/**
	 * Creates a default {@link CameraModel} instance, ready to be persisted.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the builder instance to be used.
	 * @since 1.0
	 */
	public CameraModelBuilder createDefaultCameraModel() {
		setInstance(createInstance());
		return this;
	}

	/**
	 * Persists the built {@link CameraModel} instance then flush the current session.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the builder instance after this action.
	 * @since 1.0
	 */
	public CameraModelBuilder persistAndFlush() {
		Assert.notNull(cameraModelDAO, "cameraModelDAO must not be null at this time");

		cameraModelDAO.saveEntity(getObject());
		cameraModelDAO.flushSession();
		return this;
	}

	/**
	 * Creates a {@link CameraModel} instance with default values. These ones have a functional
	 * sense.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the built instance.
	 * @since 1.0
	 */
	private CameraModel createInstance() {
		Assert.notNull(cameraBrandDAO, "cameraBrandDAO must not be null at this time");

		final CameraModel defaultCameraModel = new CameraModel();
		defaultCameraModel.setCameraBrand(CameraBrandBuilder.with(cameraBrandDAO).createDefaultCameraBrand().persistAndFlush().getObject());
		defaultCameraModel.setName("D40");

		return defaultCameraModel;
	}
}
